package com.demo.supplier.interceptor;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.demo.supplier.constant.ApiConstants;
import com.demo.supplier.entity.OperationLog;
import com.demo.supplier.service.LogService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.time.LocalDateTime;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;

/**
 * 操作日志拦截器
 * 
 * @author demo
 */
@Slf4j
@Component
public class LogInterceptor implements HandlerInterceptor {

    @Autowired
    private LogService logService;

    @Autowired
    private ApiConstants apiConstants;

    private static final String START_TIME_ATTRIBUTE = "startTime";

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 记录请求开始时间
        request.setAttribute(START_TIME_ATTRIBUTE, System.currentTimeMillis());
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        // 这里可以处理一些后置逻辑
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        try {
            // 排除不需要记录日志的请求
            String uri = request.getRequestURI();
            if (shouldSkipLogging(uri)) {
                return;
            }

            // 计算执行时间
            Long startTime = (Long) request.getAttribute(START_TIME_ATTRIBUTE);
            Long executionTime = startTime != null ? System.currentTimeMillis() - startTime : 0L;

            // 构建操作日志
            OperationLog operationLog = new OperationLog();
            
            // 从请求属性中获取用户信息（认证拦截器设置的）
            Long userId = (Long) request.getAttribute("userId");
            String username = (String) request.getAttribute("username");
            
            operationLog.setUserId(userId);
            operationLog.setUsername(username);
            operationLog.setOperation(getOperation(request.getMethod(), uri));
            operationLog.setModule(getModule(uri));
            operationLog.setDescription(getDescription(request.getMethod(), uri));
            operationLog.setIp(getClientIp(request));
            operationLog.setUserAgent(request.getHeader("User-Agent"));
            operationLog.setRequestData(getRequestData(request));
            operationLog.setExecutionTime(executionTime);
            operationLog.setCreateTime(LocalDateTime.now());
            
            // 设置响应数据和异常信息
            if (ex != null) {
                // 有异常，记录错误信息
                operationLog.setResponseData("操作失败: " + ex.getMessage());
                operationLog.setDescription(operationLog.getDescription() + " (失败)");
            } else {
                // 没有异常，记录HTTP状态码
                int status = response.getStatus();
                if (status >= 400) {
                    // HTTP错误状态码
                    operationLog.setResponseData("操作失败: HTTP 状态码 " + status);
                    operationLog.setDescription(operationLog.getDescription() + " (失败)");
                } else {
                    // 成功
                    operationLog.setResponseData("操作成功: HTTP 状态码 " + status);
                }
            }

            // 异步保存日志
            logService.saveOperationLog(operationLog);

        } catch (Exception e) {
            log.error("记录操作日志失败", e);
        }
    }

    /**
     * 判断是否跳过日志记录
     */
    private boolean shouldSkipLogging(String uri) {
        return uri.contains(apiConstants.getLoginPath()) ||
               uri.contains(apiConstants.getLogoutPath()) ||
               uri.contains(apiConstants.buildApiPath(ApiConstants.AUTH + "/userinfo")) ||
               uri.contains(apiConstants.buildApiPath(ApiConstants.LOGS)) ||
               uri.contains("/doc.html") ||
               uri.contains("/swagger-") ||
               uri.contains("/v2/api-docs") ||
               uri.contains("/webjars/") ||
               uri.contains("/favicon.ico");
    }

    /**
     * 获取操作类型
     */
    private String getOperation(String method, String uri) {
        switch (method.toUpperCase()) {
            case "POST":
                return "CREATE";
            case "PUT":
                return "UPDATE";
            case "DELETE":
                return "DELETE";
            case "GET":
                return "QUERY";
            default:
                return method.toUpperCase();
        }
    }

    /**
     * 获取模块名称
     */
    private String getModule(String uri) {
        if (uri.contains(ApiConstants.USERS)) {
            return "用户管理";
        } else if (uri.contains(ApiConstants.SUPPLIERS)) {
            return "供应商管理";
        } else if (uri.contains(ApiConstants.FILES)) {
            return "文件管理";
        } else {
            return "系统管理";
        }
    }

    /**
     * 获取操作描述
     */
    private String getDescription(String method, String uri) {
        String module = getModule(uri);
        String operation = getOperation(method, uri);
        
        switch (operation) {
            case "CREATE":
                return "创建" + module.replace("管理", "");
            case "UPDATE":
                return "更新" + module.replace("管理", "");
            case "DELETE":
                return "删除" + module.replace("管理", "");
            case "QUERY":
                return "查询" + module.replace("管理", "");
            default:
                return operation + " " + module;
        }
    }

    /**
     * 获取请求数据
     */
    private String getRequestData(HttpServletRequest request) {
        try {
            Map<String, Object> params = new HashMap<>();
            
            // 获取查询参数
            Enumeration<String> paramNames = request.getParameterNames();
            while (paramNames.hasMoreElements()) {
                String paramName = paramNames.nextElement();
                params.put(paramName, request.getParameter(paramName));
            }
            
            return JSONUtil.toJsonStr(params);
        } catch (Exception e) {
            return "";
        }
    }

    /**
     * 获取响应状态
     */
    private String getResponseStatus(HttpServletResponse response) {
        return String.valueOf(response.getStatus());
    }

    /**
     * 获取客户端IP
     */
    private String getClientIp(HttpServletRequest request) {
        String ip = request.getHeader("X-Forwarded-For");
        if (StrUtil.isBlank(ip) || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (StrUtil.isBlank(ip) || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (StrUtil.isBlank(ip) || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }
}